package com.bl.student.service.vo.roaste;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.UUID;

/**
 * Created by liangweikang on 20/10/21.
 */
public abstract class AbstractModel implements Serializable {

    private static final long serialVersionUID = 1L;

    public static int generateID() {
        return UUID.randomUUID().hashCode();
    }

    public static <T extends AbstractModel> T create(byte[] data, Class<T> clazz)
            throws IOException {
        T model;

        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
            ObjectInputStream ois = new ObjectInputStream(inputStream);
            Object obj = ois.readObject();
            if (!clazz.isInstance(obj)) {
                throw new IOException("Class " + obj.getClass().getSimpleName() +
                        " is NOT assignable from class " + clazz.getSimpleName());
            }
            model = (T) obj;
        } catch (IOException e) {
            throw new IOException(e);
        } catch (ClassNotFoundException e) {
            throw new IOException(e);
        }

        model.afterCreate();
        return model;
    }

    void afterCreate() {

    }

    void doRecover(AbstractModel model) throws IOException {
        Field[] fields = this.getClass().getDeclaredFields();

        for (Field field : fields) {
            if (Modifier.isTransient(field.getModifiers()))
                continue;
            if (Modifier.isVolatile(field.getModifiers()))
                continue;
            if (Modifier.isStatic(field.getModifiers()))
                continue;
            if (Modifier.isFinal(field.getModifiers()))
                continue;

            try {
                field.set(this, field.get(model));
            } catch (IllegalAccessException e) {
                throw new IOException(e);
            }
        }
    }

    public final byte[] backup() throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(256);

        try {
            ObjectOutputStream oos = new ObjectOutputStream(outputStream);
            oos.writeObject(this);
        } catch (IOException e) {
            throw new IOException(e);
        }

        return outputStream.toByteArray();
    }

    public final void recover(byte[] data) throws IOException {
        AbstractModel model = create(data, this.getClass());
        doRecover(model);
    }
}
